package io.legado.app.utils


/**
 * 排序比较
 */
object AlphanumComparator : Comparator<String> {


    /**
     * 比较两个字符串 s1 和 s2。
     * 比较基于字符串中的子串的数值和字典顺序。
     * 数值子串按其数值大小比较，而非数值子串按字典顺序比较。
     *
     * @param s1 第一个要比较的字符串。
     * @param s2 第二个要比较的字符串。
     * @return 返回负数表示 s1 小于 s2，0 表示两者相等，正数表示 s1 大于 s2。
     */
    override fun compare(s1: String, s2: String): Int {
        var thisMarker = 0
        var thatMarker = 0
        val s1Length = s1.length
        val s2Length = s2.length

        while (thisMarker < s1Length && thatMarker < s2Length) {
            val thisChunk = getChunk(s1, s1Length, thisMarker)
            thisMarker += thisChunk.length

            val thatChunk = getChunk(s2, s2Length, thatMarker)
            thatMarker += thatChunk.length

            // 如果两个子串都包含数字字符，则按数值排序。
            var result: Int
            if (isDigit(thisChunk[0]) && isDigit(thatChunk[0])) {
                // 通过长度进行简单的子串比较。
                val thisChunkLength = thisChunk.length
                result = thisChunkLength - thatChunk.length
                // 如果长度相等，则比较第一个不同的数字。
                if (result == 0) {
                    for (i in 0 until thisChunkLength) {
                        result = thisChunk[i] - thatChunk[i]
                        if (result != 0) {
                            return result
                        }
                    }
                }
            } else {
                result = thisChunk.compareTo(thatChunk)
            }

            if (result != 0) {
                return result
            }
        }

        return s1Length - s2Length
    }


    /**
     * 从给定字符串中提取一个特定类型的字符块。
     *
     * 此函数旨在从一个较大的字符串中提取出一块连续的子字符串，
     * 这块子字符串要么完全由数字组成，要么完全由非数字字符组成，
     * 具体取决于起始位置的字符类型。
     *
     * @param string 待提取的源字符串。
     * @param length 源字符串的总长度。
     * @param marker 提取开始的位置标记。
     * @return 返回提取出的字符块，该块由相同类型的字符组成（全为数字或全为非数字字符）。
     */
    private fun getChunk(string: String, length: Int, marker: Int): String {
        // 初始化当前指针位置为传入的标记位置
        var current = marker
        // 创建一个可变字符串对象来存储提取的字符块
        val chunk = StringBuilder()
        // 获取当前指针位置的字符
        var c = string[current]
        // 将当前字符添加到字符块中
        chunk.append(c)
        // 向前移动指针位置
        current++

        // 判断当前字符是否为数字，以决定后续添加到字符块中的字符类型
        if (isDigit(c)) {
            // 如果当前字符是数字，继续添加后续的数字字符到字符块中
            while (current < length) {
                c = string[current]
                // 遇到非数字字符时停止添加
                if (!isDigit(c)) {
                    break
                }
                // 将数字字符添加到字符块中
                chunk.append(c)
                // 向前移动指针位置
                current++
            }
        } else {
            // 如果当前字符不是数字，继续添加后续的非数字字符到字符块中
            while (current < length) {
                c = string[current]
                // 遇到数字字符时停止添加
                if (isDigit(c)) {
                    break
                }
                // 将非数字字符添加到字符块中
                chunk.append(c)
                // 向前移动指针位置
                current++
            }
        }
        // 返回构建好的字符块字符串
        return chunk.toString()
    }

    private fun isDigit(ch: Char): Boolean {
        return ch in '0'..'9'
    }
}
